#include "domxml.h"

DomNode DomItemBase::toNode() const
{
    return DomNode(m_Element);
}

DomValue DomItemBase::toValue() const
{
    return DomValue(m_Element);
}

DomValue::DomValue(const QDomElement &e) : inherit(e),
    m_Value(m_Element.firstChild().toText())
{
}

DomNode DomNode::addNode(const QString &name)
{
    QDomElement e = m_Element.ownerDocument().createElement(name);
    m_Element.appendChild(e);
    return DomNode(e);
}

DomValue DomNode::addValue(const QString &name)
{
    QDomElement e = m_Element.ownerDocument().createElement(name);
    e.appendChild(m_Element.ownerDocument().createTextNode(""));
    m_Element.appendChild(e);
    return DomValue(e);
}

DomValue DomNode::addValue(const QString &name, const QString &value)
{
    DomValue e = addValue(name);
    e.setValue(value);
    return e;
}
DomValue DomNode::addValue(const QString &name, const char *value)
{
    DomValue e = addValue(name);
    e.setValue(QString(value));
    return e;
}

DomValue DomNode::addValue(const QString &name, int value)
{
    DomValue e = addValue(name);
    e.setValue(value);
    return e;
}

DomValue DomNode::addValue(const QString &name, long long value)
{
    DomValue e = addValue(name);
    e.setValue(value);
    return e;
}

DomValue DomNode::addValue(const QString &name, bool value)
{
    DomValue e = addValue(name);
    e.setValue(value);
    return e;
}

DomValue DomNode::addValue(const QString &name, unsigned int value)
{
    DomValue e = addValue(name);
    e.setValue(value);
    return e;
}

DomValue DomNode::addValue(const QString &name, unsigned short value)
{
    DomValue e = addValue(name);
    e.setValue(value);
    return e;
}

QDomElement DomNode::findElement(const QString &path) const
{
    QStringList list = path.split("/");

    QDomElement parent = m_Element;
    for (int i = 0; i < list.count(); i++)
    {
        if (!parent.isNull())
        {
            QDomElement item = parent.firstChildElement();
            while (!item.isNull() && item.tagName() != list[i])
            {
                item = item.nextSiblingElement();
            }
            parent = item;
        }
    }
    return parent;
}

DomNode DomNode::node(const QString &path) const
{
    return DomNode(findElement(path));
}

DomValue DomNode::value(const QString &path) const
{
    return DomValue(findElement(path));
}

DomItemList DomNode::nodes(const QString &path) const
{
    QDomElement parent = m_Element;
    QString name = path;

    int index = path.lastIndexOf("/");
    if (index >= 0)
    {
        parent = findElement(path.left(index));
        name = path.mid(index + 1);
    }

    DomItemList findList;

    QDomElement item = parent.firstChildElement();
    while (!item.isNull())
    {
        if (item.tagName() == name)
        {
            findList.m_ElementList.append(item);
        }
        item = item.nextSiblingElement();
    }

    return findList;
}

DomNode DomNode::firstChild() const
{
    return DomNode(m_Element.firstChildElement());
}

DomNode DomNode::nextSibling() const
{
    return DomNode(m_Element.nextSiblingElement());
}

QTextCodec* DomContent::m_pTextCodec = QTextCodec::codecForName("UTF-8");

QTextCodec* DomContent::textCodec()
{
    return m_pTextCodec;
}

void DomContent::setTextCodec(QTextCodec *c)
{
    if (c != NULL)
    {
        m_pTextCodec = c;
    }
}

QString DomContent::string(const QByteArray &v)
{
    return m_pTextCodec->toUnicode(v);
}

QByteArray DomContent::array(const QString &v)
{
    return m_pTextCodec->fromUnicode(v);
}

QString DomContent::string() const
{
    return isNull() ? "" : m_Content.toString();
}

void DomContent::setString(const QString &v)
{
    clear();
    if (v.length() > 0)
    {
        m_Content.setContent(v);
    }
}

DomNode DomContent::root() const
{
    return DomNode(m_Content.firstChildElement());
}

void DomContent::setRoot(const QString &name)
{
    clear();

    QDomProcessingInstruction p = m_Content.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"" + m_pTextCodec->name() + "\"");
    m_Content.appendChild(p);

    QDomElement root = m_Content.createElement(name);
    m_Content.appendChild(root);
}

DomNode DomContent::createRoot(const QString &name)
{
    setRoot(name);
    return root();
}

bool DomContent::decode(const QByteArray& d)
{
    clear();
    return m_Content.setContent(d, &m_sErrorString);
}

QByteArray DomContent::encode() const
{
    QByteArray d;
    if (!isNull())
    {
        d = array(m_Content.toString(2));
        d.replace('\n', "\r\n");
    }
    return d;
}

bool DomContent::load(const QString &file)
{
    QFile f(file);
    if (f.open(QFile::ReadOnly))
    {
        m_Content.setContent(&f, &m_sErrorString);
        f.close();
        return true;
    }
    else
    {
        m_sErrorString = f.errorString();
    }
    return false;
}

bool DomContent::save(const QString &file)
{
    bool result = false;

    QFile f(file);
    if (f.open(QFile::WriteOnly))
    {
        if (f.write(encode()))
        {
            result = true;
        }
        else
        {
            m_sErrorString = f.errorString();
        }
        f.close();
    }
    else
    {
        m_sErrorString = f.errorString();
    }
    return result;
}

bool DomContent::saveString(const QString& file, const QString& path, const QString& val)
{
    if (path.length() > 0)
    {
        QStringList list = path.split("/");

        DomContent content;
        content.load(file);
        if (content.root().isNull())
        {
            content.createRoot("ROOT");
        }

        DomNode node = content.root();
        for (int i = 0; i < list.count() - 1; i++)
        {
            DomNode child = node.node(list[i]);
            if (child.isNull())
            {
                child = node.addNode(list[i]);
            }
            node = child;
        }

        DomValue value = node.value(list.last());
        if (value.isNull())
        {
            value = node.addValue(list.last(), val);
        }
        else
        {
            value.setValue(val);
        }
        return content.save(file);
    }
    else
    {
        return false;
    }
}

QString DomContent::loadString(const QString& file, const QString& path, const QString& def)
{
    DomContent content;
    content.load(file);
    return content.root().value(path).value(def);
}
